#include "MasterMgr.h"
#include "MasterService.h"
#include "ProtoBuffer/AllProtocol.h"
#include "Common/Utility/ServerTime.h"
MasterMgr::MasterMgr()
{
	m_mapMsgFunc[MASTER_SERVER_PROTOCOL_PING] = &MasterMgr::RecvPing;
	m_mapMsgFunc[LOGIN_REGISTE_MASTER_REQ] = &MasterMgr::RegisterFromLogin;
	m_mapMsgFunc[ZONE_REGISTE_MASTER_REQ] = &MasterMgr::RegisterFromZone;

	m_mapMsgFunc[WEB_SYN_WHITE_LST_REQ] = &MasterMgr::WhiteLstFromWeb;
	m_mapMsgFunc[WEB_TO_MASTER_REGISTER] = &MasterMgr::RegisterFromWeb;
	m_mapMsgFunc[WEB_ZONE_OPEN_STATE_REQ] = &MasterMgr::ZoneOpenFromWeb;
	m_mapMsgFunc[WEB_ALL_ZONE_OPEN_REQ] = &MasterMgr::AllZoneOpenFromWeb;
	m_mapMsgFunc[WEB_NOTIFY_ZONE_STATE_REQ] = &MasterMgr::ZoneStateReqFromWeb;

	m_bAllZoneOpen = false;
}

MasterMgr::~MasterMgr()
{
}

bool MasterMgr::Init(bool open)
{
	IMessageDispatch *pMessageDispatch = g_GetMasterService()->GetServiceMessageDispatch();
	if (nullptr == pMessageDispatch)
		return false;

	pMessageDispatch->registerServerHandler(EMODULE_ID_SERV_SYS, this);

	m_bAllZoneOpen = open;

	LogInfoFmtPrint("Master Mgr Init AllZoneOpen state:%d", open);
	return true;
}

bool MasterMgr::UnInit()
{
	IMessageDispatch *pMessageDispatch = g_GetMasterService()->GetServiceMessageDispatch();
	if (nullptr == pMessageDispatch)
		return false;

	pMessageDispatch->unregisterServerHandler(EMODULE_ID_SERV_SYS);
	return true;
}

void MasterMgr::onServerMessage(uint32_t actionId, RECV_PACKAGE &package)
{
	MSGFUNC::iterator iter = m_mapMsgFunc.find(actionId);
	MSGFUNC::iterator iterEnd = m_mapMsgFunc.end();
	if (iter == iterEnd)
	{
		LogErrFmtPrint("masterMgr recv msg cannt find handle actionId:%d, moudle:%d", actionId, package.moduleId);
		return;
	}
	(this->*iter->second)(package);
}

bool MasterMgr::RecvPing(RECV_PACKAGE &package)
{
	//g_GetMasterService()->SendDataToServer(package.session->GetUserData().v32, EMODULE_ID_SERV_SYS, MASTER_SERVER_PROTOCOL_PING);
	return true;
}

bool MasterMgr::RegisterFromLogin(RECV_PACKAGE &package)
{
	bool result = false;
	bool retCode = false;
	LoginRegisterReq lregisterReq;
	LoginRegisterRsp lRegisterRsp;
	lRegisterRsp.set_allzoneopen(m_bAllZoneOpen);
	lRegisterRsp.set_retcode(RET_FAIL);

	uint32_t loginId = 0;

	retCode = lregisterReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
	MMOLOG_PROCESS_ERROR(retCode);

	MMOLOG_PROCESS_ERROR(package.session != nullptr);
	loginId = lregisterReq.id();

	retCode = g_GetMasterService()->AddLoginSession(loginId, package.session);
	if (!retCode)
	{
		LogErrFmtPrint("login id repeated in masterServer, loginid:%d", loginId);
		MMOLOG_PROCESS_ERROR(retCode);
	}

	retCode = ZonesInfoToLogin(lRegisterRsp);
	MMOLOG_PROCESS_ERROR(retCode);

	result = true;
	lRegisterRsp.set_retcode(RET_SUCCESS);
	LogDebugFmtPrint("login server register master success, loginId:%d", loginId);
Exit0:
	retCode = g_GetMasterService()->SendData(package.session, EMODULE_ID_SERV_SYS, MASTER_REGISTE_LOGIN_RSP, &lRegisterRsp);
	if (!retCode)
	{
		LogErrFmtPrint("RegisterFromLogin, send data err, loginId:%d", loginId);
	}
	return result;
}


bool MasterMgr::ZonesInfoToLogin(LoginRegisterRsp& lRegisterRsp)
{
    bool result = false;
    //bool retCode = false;

	REPEATED_UINT32 *pWhitelst = nullptr;
	REPEATED_UINT32 *precommZoneIds = nullptr;
	ZoneInfo *pZone = nullptr;
	ZIDZONEMAP::iterator iter = m_zones.begin();
	ZIDZONEMAP::iterator iterEnd = m_zones.end();

	char buf[16];
	int length = 0;

	for (; iter != iterEnd; iter++)
	{
		pZone = lRegisterRsp.add_zones();
		if (pZone == nullptr)
		{
			LogErrFmtPrint("ZonesInfoToLogin err, nofity.add_zones() == null");
			continue;
		}
		MServerZoneInfo &zone = iter->second;
		list<uint32_t>::iterator cIterEnd = zone.channels.end();
		list<uint32_t>::iterator cIter = zone.channels.begin();
		string channbuf;

		pZone->set_ip(zone.ip);
		pZone->set_name(zone.name);
		pZone->set_port(zone.port);
		pZone->set_zid(zone.zid);
		pZone->set_whitelst(zone.whiteLst);
		pZone->set_zstate(zone.zstate);
		for (; cIter != cIterEnd; cIter++)
		{
			pZone->add_channelid(*cIter);

			length = snprintf(buf, 16, "%d,", *cIter);
			if (length > 15)
				continue;
			buf[length + 1] = '\0';
			channbuf += buf;
		}

		LogInfoFmtPrint("master notify login zones, zid:%d, name:%s, whitelist:%d, zoneState:%d, ip:%s, port:%d, channs:%s", 
			zone.zid, zone.name.c_str(), zone.whiteLst, zone.zstate, zone.ip.c_str(), zone.port, channbuf.c_str());
	}
	lRegisterRsp.set_allzoneopen(m_bAllZoneOpen);

	pWhitelst = lRegisterRsp.mutable_whitelst();
	MMOLOG_PROCESS_ERROR(pWhitelst != nullptr);

	precommZoneIds = lRegisterRsp.mutable_recommendzoneids();
	MMOLOG_PROCESS_ERROR(precommZoneIds != nullptr);

	pWhitelst->CopyFrom(m_whiteLst);
	precommZoneIds->CopyFrom(m_recommZoneIds);

    result = true;
Exit0:
	return result;
}

bool MasterMgr::RegisterFromZone(RECV_PACKAGE &package)
{
	bool result = false;
	bool retCode = false;
	ZoneRegisterReq zoneRegister;
	uint32_t zid = 0;
	uint32_t channelId = 0;

	ZoneRegisterRsp zoneRsp;
	MServerZoneInfo mzone;
	zoneRsp.set_retcode(RET_FAIL);

	MMOLOG_PROCESS_ERROR(package.session != nullptr);
	retCode = zoneRegister.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
	MMOLOG_PROCESS_ERROR(retCode);

	zid = zoneRegister.zid();
	retCode = g_GetMasterService()->AddZoneSession(zid, package.session);
	if (!retCode)
	{
		LogErrFmtPrint("zid id repeated in masterServer, zid:%d", mzone.zid);
		MMOLOG_PROCESS_ERROR(false);
	}

	mzone.ip = zoneRegister.ip();
	mzone.name = zoneRegister.name();
	mzone.whiteLst = zoneRegister.whitelst();
	mzone.zid = zoneRegister.zid();
	mzone.port = zoneRegister.port();
	mzone.datalogdb = zoneRegister.datalogdbip();
	mzone.zonelogdb = zoneRegister.zonelogdbip();

	for (int i = 0; i < zoneRegister.channelids_size(); i++)
	{
		channelId = zoneRegister.channelids(i);
		mzone.channels.push_back(channelId);
	}
	m_zones[mzone.zid] = mzone;

	retCode = NotifyLoginZones();
	MMOLOG_PROCESS_ERROR(retCode);

	zoneRsp.set_retcode(RET_SUCCESS);
	LogDebugFmtPrint("recv register from gate server, zid:%d", mzone.zid);

	result = true;

	retCode = NotifyWebZones();
	MMOLOG_PROCESS_ERROR(retCode);

Exit0:
	retCode = g_GetMasterService()->SendData(package.session, EMODULE_ID_SERV_SYS, ZONE_REGISTE_MASTER_RSP, &zoneRsp);
	if (!retCode)
	{
		LogErrFmtPrint("RegisterFromZone, send data err, zid:%d", zid);
	}
	return result;
}

bool MasterMgr::ClearZoneInfo(uint32_t zid)
{
	bool result = false;
	bool retCode = false;

	m_zones.erase(zid);

	LogErrFmtPrint("master server recv zone disconnect event, zoneId:%d", zid);
	retCode = NotifyLoginZones();
	MMOLOG_PROCESS_ERROR(retCode);

	result = true;
Exit0:
	return result;
}


bool MasterMgr::NotifyLoginZones()
{
	ZIDZONEMAP::iterator iter = m_zones.begin();
	ZIDZONEMAP::iterator iterEnd = m_zones.end();
	list<uint32_t>::iterator cIter, cIterEnd;
	NofityNewZoneToLogin nofity;

	char buf[16];
	int length = 0;

	for (; iter != iterEnd; iter++)
	{
		string channbuf;
		ZoneInfo *pZone = nofity.add_zones();
		if (pZone == nullptr)
		{
			LogErrFmtPrint("notifyloginzones err, nofity.add_zones() == null");
			continue;
		}
		MServerZoneInfo &zone = iter->second;
		cIterEnd = zone.channels.end();
		cIter = zone.channels.begin();
		pZone->set_ip(zone.ip);
		pZone->set_name(zone.name);
		pZone->set_port(zone.port);
		pZone->set_zid(zone.zid);
		pZone->set_whitelst(zone.whiteLst);
		pZone->set_zstate(zone.zstate);
		for (; cIter != cIterEnd; cIter++)
		{
			pZone->add_channelid(*cIter);

			length = snprintf(buf, 16, "%d,", *cIter);
			if (length > 15)
				continue;
			buf[length + 1] = '\0';
			channbuf += buf;
		}

		LogInfoFmtPrint("master notify login zoneinfo zoneId:%d, name:%s, state:%d, channids:%s", zone.zid, zone.name.c_str(), zone.zstate, channbuf.c_str());
	}
	return g_GetMasterService()->SendDataToAllLogin(EMODULE_ID_SERV_SYS, MASTER_NOTIFY_LOGIN_NEW_ZONE, &nofity);
}

bool MasterMgr::NotifyWebZones()
{
    bool result = false;
    bool retCode = false;

	NotifyWebStartZones notify;
	ZIDZONEMAP::iterator iter = m_zones.begin();
	ZIDZONEMAP::iterator iterEnd = m_zones.end();
	list<uint32_t>::iterator chanIter, chanIterEnd;

	if (iter == iterEnd)
	{
		LogWarningFmtPrint("NotifyWebZones, no zone register to master, please wait or check..");
		return true;
	}

	for (; iter != iterEnd; iter++)
	{
		NotifyWebStartZones_StartZone* pZones = notify.add_zones();
		pZones->set_zid(iter->second.zid);
		pZones->set_zonename(iter->second.name);
		pZones->set_zonelogdb(iter->second.zonelogdb);
		pZones->set_datalogdb(iter->second.datalogdb);

		chanIter = iter->second.channels.begin();
		chanIterEnd = iter->second.channels.end();
		for (; chanIter != chanIterEnd; chanIter++)
			pZones->add_chanids(*chanIter);
	}

	retCode = g_GetMasterService()->SendDataToWeb(MASTER_NOTIFY_WEB_START_ZONES, &notify);
	MMOLOG_PROCESS_ERROR(retCode);

    result = true;
Exit0:
	return result;
}

bool MasterMgr::NotifyLoginWhiteList()
{
    bool result = false;
    bool retCode = false;
	NofityLoginWhiteLst notifywhite;
	REPEATED_UINT32 *pWhitelst = nullptr;
	REPEATED_UINT32 *precommendZoneIds = nullptr;
	REPEATED_UNOPEN_ZONES *punOpenZones = nullptr;

	pWhitelst = notifywhite.mutable_whitelst();
	MMOLOG_PROCESS_ERROR(pWhitelst != nullptr);

	precommendZoneIds = notifywhite.mutable_whitelst();
	MMOLOG_PROCESS_ERROR(precommendZoneIds != nullptr);

	punOpenZones = notifywhite.mutable_unopenzones();
	MMOLOG_PROCESS_ERROR(punOpenZones != nullptr);

	pWhitelst->CopyFrom(m_whiteLst);
	precommendZoneIds->CopyFrom(m_recommZoneIds);
	punOpenZones->CopyFrom(m_unopenZones);

	retCode = g_GetMasterService()->SendDataToAllLogin(EMODULE_ID_SERV_SYS,MASTER_TO_LOGIN_WHITE_LST, &notifywhite);
	MMOLOG_PROCESS_ERROR(retCode);

    result = true;
Exit0:
	return result;
}

bool MasterMgr::RegisterFromWeb(RECV_PACKAGE &package)
{
    bool result = false;
	bool retCode = false;
	WebToMasterRegiste registe;

	MMOLOG_PROCESS_ERROR(package.session != nullptr);

	retCode = g_GetMasterService()->AddWebSession(1, package.session);
	if (!retCode)
	{
		LogErrFmtPrint("web id repeated in masterServer");
		MMOLOG_PROCESS_ERROR(false);
	}

	m_whiteLst.Clear();
	m_whiteLst = registe.whitelst();

	m_recommZoneIds.Clear();
	m_recommZoneIds = registe.recommendzoneids();

	m_unopenZones.Clear();
	m_unopenZones.CopyFrom(registe.unopenzones());

	retCode = NotifyLoginWhiteList();
	MMOLOG_PROCESS_ERROR(retCode);

	retCode = NotifyLoginZones();
	MMOLOG_PROCESS_ERROR(retCode);

	retCode = NotifyWebZones();
	MMOLOG_PROCESS_ERROR(retCode);

	LogInfoFmtPrint("web register from web, success");
    result = true;
Exit0:
	return result;
}

MServerZoneInfo* MasterMgr::GetMasterZoneInfo(uint32_t zid)
{
	ZIDZONEMAP::iterator iter = m_zones.find(zid);
	ZIDZONEMAP::iterator iterEnd = m_zones.end();

	if (iter != iterEnd)
		return &iter->second;

	return nullptr;
}

bool MasterMgr::ZoneOpenFromWeb(RECV_PACKAGE& package)
{
    bool result = false;
    bool retCode = false;
	WebToMasterZoneOpenState openReq;
	uint32_t zid = 0;
	GMResult webRsp;
	MServerZoneInfo *pmZone = nullptr;

	retCode = openReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
	MMOLOG_PROCESS_ERROR(retCode);
	zid = openReq.zid();
	webRsp.set_webid(openReq.webid());
	webRsp.set_retcode(RET_FAIL);

	pmZone = GetMasterZoneInfo(zid);
	if (pmZone == nullptr)
	{
		LogErrFmtPrint("cant find zid info, open zone fail, zid:%d, open:%d", zid, openReq.whitelst());
		MMOLOG_PROCESS_ERROR(false);
	}

	webRsp.set_retcode(RET_SUCCESS);
	pmZone->whiteLst = openReq.whitelst();
	pmZone->zonelstId = openReq.zonelstid();

	retCode = NotifyLoginZoneStates(*pmZone);
	MMOLOG_PROCESS_ERROR(retCode);

    result = true;
Exit0:
	retCode = g_GetMasterService()->SendData(package.session, EMODULE_ID_SERV_SYS, WEB_ZONE_OPEN_STATE_RSP, &webRsp);
	if (!retCode)
		LogErrFmtPrint("ZoneOpenFromWeb, send data err zid=%d", zid);
	return result;
}

bool MasterMgr::AllZoneOpenFromWeb(RECV_PACKAGE &package)
{
    bool result = false;
	bool retCode = false;
	{
		WebToMasterAllZoneOpenReq allzone;
		retCode = allzone.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
		MMOLOG_PROCESS_ERROR(retCode);

		LogInfoFmtPrint("AllZoneOpenFromWeb, old:%d  new:%d, webid:%s", m_bAllZoneOpen, allzone.allzoneopen(), allzone.webid().c_str());
		m_bAllZoneOpen = allzone.allzoneopen();

		NofityLoginAllZoneOpenState loginAllZone;
		loginAllZone.set_allzoneopen(m_bAllZoneOpen);

		retCode = g_GetMasterService()->SendDataToAllLogin(EMODULE_ID_SERV_SYS,MASTER_TO_LOGIN_ALL_ZONE_OPEN_STATE, &loginAllZone);
		MMOLOG_OUTPUT_ERROR(retCode);

		GMResult webRsp;
		webRsp.set_retcode(RET_SUCCESS);
		webRsp.set_webid(allzone.webid());
		retCode = g_GetMasterService()->SendData(package.session, EMODULE_ID_SERV_SYS, WEB_ALL_ZONE_OPEN_RSP, &webRsp);
		MMOLOG_PROCESS_ERROR(retCode);
	}

    result = true;
Exit0:
	return result;
}

bool MasterMgr::WhiteLstFromWeb(RECV_PACKAGE &package)
{
    bool result = false;
	bool retCode = false;
	WebToMasterSynWhiteLstReq whiteReq;
	NofityLoginWhiteLst notifywhite;
	REPEATED_UINT32 *pWhitelst = nullptr;
	REPEATED_UINT32 *precommZoneIds = nullptr;
	REPEATED_UNOPEN_ZONES *punOpenZones = nullptr;
	GMResult wRsp;

	retCode = whiteReq.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
	MMOLOG_PROCESS_ERROR(retCode);

	wRsp.set_webid(whiteReq.webid());
	wRsp.set_retcode(RET_SUCCESS);

	if (whiteReq.whitelst_size() > 0)
	{
		m_whiteLst.Clear();
		m_whiteLst.CopyFrom(whiteReq.whitelst());

		pWhitelst = notifywhite.mutable_whitelst();
		MMOLOG_PROCESS_ERROR(pWhitelst != nullptr);

		pWhitelst->CopyFrom(m_whiteLst);
	}

	if (whiteReq.recommendzoneids_size() > 0)
	{
		m_recommZoneIds.Clear();
		m_recommZoneIds.CopyFrom(whiteReq.recommendzoneids());
		precommZoneIds = notifywhite.mutable_recommendzoneids();
		MMOLOG_PROCESS_ERROR(precommZoneIds != nullptr);

		precommZoneIds->CopyFrom(notifywhite.recommendzoneids());
	}
	if (whiteReq.unopenzones_size() > 0)
	{
		m_unopenZones.Clear();
		m_unopenZones.CopyFrom(whiteReq.unopenzones());
		punOpenZones = notifywhite.mutable_unopenzones();
		MMOLOG_PROCESS_ERROR(punOpenZones != nullptr);

		punOpenZones->CopyFrom(whiteReq.unopenzones());
	}


	LogInfoFmtPrint("WhiteLstFromWeb, webid:%s, count:%d, recomZonesCount:%d", whiteReq.webid().c_str(), whiteReq.whitelst_size(), whiteReq.recommendzoneids_size());

	retCode = g_GetMasterService()->SendDataToAllLogin(EMODULE_ID_SERV_SYS, MASTER_TO_LOGIN_WHITE_LST, &notifywhite);
	MMOLOG_OUTPUT_ERROR(retCode);

    result = true;
Exit0:
	retCode = g_GetMasterService()->SendData(package.session, EMODULE_ID_SERV_SYS, WEB_SYN_WHITE_LST_RSP, &wRsp);
	if (!retCode)
		LogErrFmtPrint("WhiteLstFromWeb, send data err");
	return result;
}

bool MasterMgr::ZoneStateReqFromWeb(RECV_PACKAGE& package)
{
    bool result = false;
    bool retCode = false;

	WebZoneStateReq zStates;
	ZoneState zS;
	ZONE_STATE_MAP::iterator iter;
	ZONE_STATE_MAP::iterator iterEnd;
	MServerZoneInfo* pMServer = nullptr;  
	GMResult  webRsp; 

	retCode = zStates.ParseFromArray(package.dataAfterHead, package.sizeAfterHead);
	MMOLOG_PROCESS_ERROR(retCode);

	for (int i = 0; i < zStates.zonestates_size(); i++)
	{
		zS = zStates.zonestates(i);
		pMServer = GetMasterZoneInfo(zS.zid());
		if (pMServer)
		{
			pMServer->zstate = zS.state();
			if (zS.channs_size() > 0)
				pMServer->channels.clear();
				
			for (int j = 0; j < zS.channs_size(); j++)
				pMServer->channels.push_back(zS.channs(j));
		}
		else
			LogErrFmtPrint("register cannt find zone info, zid:%d", zS.zid());

		LogDebugFmtPrint("recv zone state req from web, zid:%d, state:%d, webid:%s", zS.zid(), zS.state(), zStates.webid().c_str());
	}

	retCode = NotifyLoginZones();
	MMOLOG_PROCESS_ERROR(retCode);

	webRsp.set_retcode(RET_SUCCESS);
	webRsp.set_webid(zStates.webid());
	retCode = g_GetMasterService()->SendData(package.session, EMODULE_ID_SERV_SYS, WEB_NOTIFY_ZONE_STATE_RSP, &webRsp);
	MMOLOG_PROCESS_ERROR(retCode);

    result = true;
Exit0:
	return result;
}

bool MasterMgr::NotifyLoginZoneStates(MServerZoneInfo& zone)
{
    bool result = false;
    bool retCode = false;

	//同步给登陆服
	NotifyLoginOpenState nfloginState;
	nfloginState.set_zid(zone.zid);
	nfloginState.set_whitelst(zone.whiteLst);
	nfloginState.set_zonelstid(zone.zonelstId);

	std::list<uint32_t>::iterator citer = zone.channels.begin();
	std::list<uint32_t>::iterator citerEnd = zone.channels.end();
	for (; citer != citerEnd; citer++)
	{
		nfloginState.add_channels(*citer);
	}

	retCode = g_GetMasterService()->SendDataToAllLogin(EMODULE_ID_SERV_SYS, MASTER_TO_LOGIN_OPEN_STATE, &nfloginState);
	MMOLOG_PROCESS_ERROR(retCode);

    result = true;
Exit0:
	return result;
}